home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / The Weakest Link / source / DNS code / CDNSAction.cp next >
Encoding:
Text File  |  2001-06-23  |  31.5 KB  |  1,119 lines

  1. // =================================================================================
  2. //    CDNSAction.cp            ©1999 Sustainable Softworks All rights reserved.
  3. // =================================================================================
  4. //    Perform DNS Deferral
  5. //
  6. //    IPNetRouter does DNS forwarding using the NAT feature when there
  7. //    is no PPP interface or PPP is connected.  The NAT module is
  8. //  programmed to translate DNS requests to our local address to
  9. //  the currently configured DNS server, and the IP module forwards
  10. //    them.
  11. //
  12. //    When PPP is disconnected, the DNS NAT mappings are disabled so
  13. //  this module can receive DNS traffic and perform DNS Deferral.
  14. //    We intercept simple DNS lookup requests and generate an
  15. //    intermediate response at 2 second intervals until PPP comes
  16. //    back on-line (or we time out).  The purpose of these intermediate
  17. //    responses is to prevent the clients DNR from timing out while
  18. //  waiting for PPP to connect.
  19. //
  20. //    We never actually forward a DNS request on behalf of a client,
  21. //    rather, we string the client along with one CNAME after another
  22. //    until the DNS port mappings are back online, then we tell the
  23. //    client to retry the original DNS request, but this time the request
  24. //  is redirected to a real Name Server by the NAT module.
  25.  
  26. #include "CompileFlags.h"
  27. #include "CDNSAction.h"
  28. #include "CDNSConst.h"
  29. //#include "myDNS.h"
  30. #include "CResidentIfInfo.h"
  31. #include "CConnectionData.h"
  32. #include "CInterfacesData.h"
  33. #include "CInterfacesAction.h"
  34. #include "LInternetAddress.h"
  35. #include "CProxyControl.h"
  36.  
  37. #include "IPRouterCommon.h"
  38. #include "MacSupport.h"
  39. #include "IPSupport.h"
  40. #include "CLogAction.h"
  41. #include <UReanimator.h>
  42. #include <LString.h>
  43. #include <LPreferencesFile.h>
  44. #include <UResourceMgr.h>
  45. #include <LArray.h>
  46. #include <LComparator.h>
  47. #include <LArrayIterator.h>
  48. #include <UMemoryMgr.h>
  49. #include <UOpenTptSupport.h>
  50.  
  51. #include "CReceiveUDPThread.h"
  52. #include "CSendUDPThread.h"
  53. #include "CTurboUDPEndpoint.h"
  54.  
  55. #include <OpenTransport.h>
  56. #include <OpenTptConfig.h>
  57. #include <OpenTptInternet.h>
  58. #include <LInternetMapper.h>
  59. #include <LOpenTptInetMapper.h>
  60. #include <OpenTptLinks.h>
  61. //#include <modnames.h>            // names of the standard OT modules.
  62.  
  63. // Globals
  64. extern CLogAction*            gLogAction;
  65. extern CResidentIfInfo*        gResInfo;
  66. extern CConnectionData*     gConnectionData;
  67. extern CInterfacesData*        gInterfacesData;
  68. extern CInterfacesAction*    gInterfacesAction;
  69. //extern CInterfacesAction*    gInterfacesAction;
  70. extern CProxyControl*        gProxyControl;
  71.  
  72. // ---------------------------------------------------------------------------------
  73. //        • CDNSAction()
  74. // ---------------------------------------------------------------------------------
  75. CDNSAction::CDNSAction()
  76. {
  77.     // other initialization
  78.     mReceiveUDPThread = nil;
  79.     mSendUDPThread = nil;
  80.     mUDPEndpoint = nil;
  81.     mResponseArray = nil;
  82.     mIsServing = false;
  83.     mWaitingToStop = false;
  84.     mWaitingToRestart = false;
  85.     mDNSRetryCount = kDNSRetryCount;
  86.     mIdleDelay = kDNSIdleDefault;
  87.     
  88.     mDNRProxyEndpoint = nil;
  89.     mDNRProxyRxThread = nil;
  90.     mDNRSourceAddr = 0;
  91.     mDNRSourcePort = 0;
  92. }
  93.  
  94.  
  95. // ---------------------------------------------------------------------------------
  96. //        • ~CDNSAction
  97. // ---------------------------------------------------------------------------------
  98. CDNSAction::~CDNSAction()
  99. {
  100.     StopServing();
  101.     if (mResponseArray) delete mResponseArray;
  102. }
  103.  
  104.  
  105. // ---------------------------------------------------------------------------------
  106. //        • Terminate
  107. // ---------------------------------------------------------------------------------
  108. void
  109. CDNSAction::Terminate(Boolean inCanWait)
  110. {
  111.     // Release thread objects we created
  112.     if (mReceiveUDPThread) mReceiveUDPThread->Abort();
  113.     if (mSendUDPThread) mSendUDPThread->Abort();
  114.     if (mDNRProxyRxThread) mDNRProxyRxThread->Abort();
  115.  
  116.     if (inCanWait) {
  117.         // Wait for threads to abort normally
  118.         UInt8 retryLimit = 24;
  119.         while (    (mReceiveUDPThread != nil)    ||
  120.                 (mSendUDPThread != nil)        ||
  121.                 (mDNRProxyRxThread != nil) ) {
  122.             LThread::Yield();
  123.             retryLimit -= 1;
  124.             if (retryLimit == 0) break;
  125.         }
  126.     }
  127.     
  128.     // if threads didn't complete, cleanup as best we can
  129.     if (mReceiveUDPThread) {
  130.         mReceiveUDPThread->DeleteThread();
  131.         mReceiveUDPThread = nil;
  132.     }
  133.     if (mSendUDPThread) {
  134.         mSendUDPThread->DeleteThread();
  135.         mSendUDPThread = nil;
  136.     }
  137.     if (mDNRProxyRxThread) {
  138.         mDNRProxyRxThread->DeleteThread();
  139.         mDNRProxyRxThread = nil;
  140.     }
  141.  
  142.     // Release the UDP Endpoint we created
  143.     if (mUDPEndpoint) {
  144.         // no longer want notification of endpoint events
  145.         mUDPEndpoint->RemoveListener(this);
  146.         delete mUDPEndpoint;
  147.         mUDPEndpoint = nil;
  148.     }
  149.     if (mDNRProxyEndpoint) {
  150.         // no longer want notification of endpoint events
  151.         //mDNRProxyEndpoint->RemoveListener(this);
  152.         delete mDNRProxyEndpoint;
  153.         mDNRProxyEndpoint = nil;
  154.     }
  155. }
  156.  
  157.  
  158. // ---------------------------------------------------------------------------------
  159. //        • StartServing
  160. // ---------------------------------------------------------------------------------
  161. Boolean
  162. CDNSAction::StartServing()
  163. {
  164.     OSErr            err = noErr;
  165.     Boolean            result = false;
  166.  
  167.     if (!mIsServing && !mWaitingToRestart) {
  168.         mWaitingToRestart = false;
  169.         try {        
  170.             //    Create a tcp endpoint to force the InetConfigurator to fire
  171.             //    (blocks until TCP/IP is ready)
  172.             err = gProxyControl->AsyncOpenAndClose();
  173.             if (err != noErr) {
  174.                 // Could not initialize OT.  Wait and try again.
  175.                 gLogAction->LogText("\p\rCDNSAction::StartServing() unexpected result initializing OT: ", err);
  176.                 if (mDNSRetryCount > 0) {
  177.                     mDNSRetryCount -= 1;
  178.                     mIdleDelay = kDNSIdleRestart;        // set idle time for restart
  179.                     OTGetTimeStamp(&mLastStamp);
  180.                     mWaitingToRestart = true;
  181.                     //this->StartIdling();
  182.                     this->StartRepeating();            
  183.                 }
  184.                 else {
  185.                     this->StopRepeating();
  186.                     mDNSRetryCount = kDNSRetryCount;
  187.                 }
  188.                 ThrowIfNil_(nil);
  189.             }
  190.  
  191.             if (!mResponseArray) {
  192.                 mResponseArray = new LArray(sizeof(dns_request_t));
  193.                 ThrowIfNil_(mResponseArray);
  194.                 //mResponseArray->SetComparator(LLongComparator::GetComparator());
  195.             }
  196.  
  197.             //    Create a UDP endpoint
  198.             if (!mUDPEndpoint) {
  199.                 mUDPEndpoint =  new CTurboUDPEndpoint(kUDPName);
  200.                 ThrowIfNil_(mUDPEndpoint);
  201.                 // Register to receive other event notifications
  202.                 mUDPEndpoint->AddListener(this);
  203.             }
  204.  
  205.             // Create thread objects for receive and transmit
  206.             if (!mReceiveUDPThread) {
  207.                 mReceiveUDPThread = new CReceiveUDPThread(
  208.                     (CObjectMaster*)    this,
  209.                     (CTurboUDPEndpoint*) mUDPEndpoint);
  210.                 ThrowIfNil_(mReceiveUDPThread);
  211.                 // Bind to DNS server port
  212.                 LInternetAddress address(0, kDNSServerPort);
  213.                 mReceiveUDPThread->Bind(address);
  214.                 mReceiveUDPThread->Resume();
  215.             }
  216.             if (!mSendUDPThread) {
  217.                 mSendUDPThread = new CSendUDPThread(
  218.                     (CObjectMaster*)    this,
  219.                     (CTurboUDPEndpoint*) mUDPEndpoint);        // coerce to re-use code
  220.                 ThrowIfNil_(mSendUDPThread);
  221.                 mSendUDPThread->Resume();
  222.             }
  223.             //    Create DNR Proxy endpoint
  224.             if (!mDNRProxyEndpoint) {
  225.                 mDNRProxyEndpoint =  new CTurboUDPEndpoint(kUDPName);
  226.                 ThrowIfNil_(mDNRProxyEndpoint);
  227.                 // Register to receive other event notifications
  228.                 //mUDPEndpoint->AddListener(this);
  229.             }
  230.  
  231.             // Create receive thread object for DNR Proxy
  232.             if (!mDNRProxyRxThread) {
  233.                 mDNRProxyRxThread = new CReceiveUDPThread(
  234.                     (CObjectMaster*)    this,
  235.                     (CTurboUDPEndpoint*) mDNRProxyEndpoint);
  236.                 ThrowIfNil_(mDNRProxyRxThread);
  237.                 // Bind to any local port
  238.                 mDNRProxyRxThread->Resume();
  239.             }
  240.  
  241.             // record server start time
  242.             if (!mIsServing) {
  243.                 ::OTGetTimeStamp(&mLastStamp);
  244.             }
  245.  
  246.             // Start idling to check for time outs
  247.             //this->StartIdling();
  248.             this->StartRepeating();
  249.             mIsServing = true;
  250.             gLogAction->LogText("\p\rDNS Action: Start DNS Deferral server");
  251.             result = true;
  252.         }
  253.         catch (...) {
  254.             gLogAction->LogText("\p\rUnexpected result while starting DNS Deferral");
  255.         } 
  256.     }
  257.     return result;
  258. }
  259.  
  260.  
  261. // ---------------------------------------------------------------------------------
  262. //        • StopServing
  263. // ---------------------------------------------------------------------------------
  264. Boolean
  265. CDNSAction::StopServing(Boolean inCanWait)
  266. {    
  267.     if (mIsServing) {
  268.         mIsServing = false;
  269.         gLogAction->LogText("\p\rDNS Action: Stop DNS Deferral Server");
  270.     }
  271.     // stop any pending restart
  272.     mWaitingToRestart = false;
  273.     // stop any pending shutdown
  274.     mWaitingToStop = false;
  275.     //this->StopIdling();
  276.     this->StopRepeating();
  277.     // clean up
  278.     Terminate(inCanWait);
  279.     mDNSRetryCount = kDNSRetryCount;        // reinitialize retry counter
  280.     return true;
  281. }
  282.  
  283.  
  284. // ---------------------------------------------------------------------------------
  285. //        • StopDeferral
  286. // ---------------------------------------------------------------------------------
  287. //    This method is called when PPP comes back on-line to indicate we should
  288. //    stop deferring clients.  We do this by telling them to lookup the
  289. //    original name they requested.
  290. void
  291. CDNSAction::StopDeferral()
  292. {    
  293.     if (mIsServing && !mWaitingToStop) {
  294.         mWaitingToStop = true;
  295.         ::OTGetTimeStamp(&mStopStamp);
  296.         gLogAction->LogText("\p\rDNS Action: Stop DNS Deferral");
  297.     }
  298. }
  299.  
  300.  
  301. // ---------------------------------------------------------------------------------
  302. //        • ResumeDeferral
  303. // ---------------------------------------------------------------------------------
  304. //    This method is called when PPP comes back on-line to indicate we should
  305. //    stop deferring clients.  We do this by telling them to lookup the
  306. //    original name they requested.
  307. void
  308. CDNSAction::ResumeDeferral()
  309. {    
  310.     if (mIsServing && mWaitingToStop) {
  311.         mWaitingToStop = false;
  312.         gLogAction->LogText("\p\rDNS Action: Resume DNS Deferral");
  313.     }
  314. }
  315.  
  316.  
  317. // ---------------------------------------------------------------------------
  318. //        • ObjectThreadDied
  319. // ---------------------------------------------------------------------------
  320. //    A threaded operation has completed.
  321. void
  322. CDNSAction::ObjectThreadDied(LThread *inThread) {
  323.  
  324.     // Receive Thread completed?
  325.     if (inThread == mReceiveUDPThread) {
  326.         // get result
  327.         long result = *((long*)inThread->GetResult());
  328.         // indicate thread no longer exists
  329.         mReceiveUDPThread = nil;
  330.         LastComplete();
  331.         // handle results
  332.         switch (result) {
  333.             case 0:                // no error
  334.             case Abort_Error:    // operation aborted
  335.                 result = 0;
  336.                 break;
  337.             default:
  338.                 gLogAction->LogText("\p\r### DNSAction CReceiveUDPThread unexpected event code: ", result);
  339.                 break;
  340.         }    // end switch
  341.  
  342.         if (result != 0) {
  343.             // Thread died due to Endpoint event, try to recover
  344.             if (mIsServing) {
  345.                 StopServing(true);
  346.                 mIdleDelay = kDNSIdleRestart;        // set idle time for restart
  347.                 OTGetTimeStamp(&mLastStamp);
  348.                 mWaitingToRestart = true;
  349.                 //this->StartIdling();
  350.                 this->StartRepeating();
  351.                 //StartServing();
  352.             }
  353.         }
  354.     }
  355.     
  356.     // Transmit Thread completed?
  357.     else if (inThread == mSendUDPThread) {
  358.         // get result
  359.         long result = *((long*)inThread->GetResult());
  360.         // indicate thread no longer exists
  361.         mSendUDPThread = nil;
  362.         LastComplete();    
  363.         // handle results
  364.         switch (result) {
  365.             case 0:                // no error
  366.             case Abort_Error:    // operation aborted
  367.                 result = 0;
  368.                 break;
  369.             default:
  370.                 gLogAction->LogText("\p\r### DNSAction CSendUDPThread unexpected event code: ", result);
  371.                 break;
  372.         }    // end switch
  373.  
  374.         if (result != 0) {
  375.             // Thread died due to Endpoint event, try to recover
  376.             if (mIsServing) {
  377.                 StopServing(true);
  378.                 mIdleDelay = kDNSIdleRestart;        // set idle time for restart
  379.                 OTGetTimeStamp(&mLastStamp);
  380.                 mWaitingToRestart = true;
  381.                 //this->StartIdling();
  382.                 this->StartRepeating();
  383.                 //StartServing();
  384.             }
  385.         }
  386.     }
  387.     // DNR Proxy Receive Thread completed?
  388.     else if (inThread == mDNRProxyRxThread) {
  389.         // get result
  390.         long result = *((long*)inThread->GetResult());
  391.         // indicate thread no longer exists
  392.         mDNRProxyRxThread = nil;
  393.         LastComplete();
  394.         // handle results
  395.         switch (result) {
  396.             case 0:                // no error
  397.             case Abort_Error:    // operation aborted
  398.                 result = 0;
  399.                 break;
  400.             default:
  401.                 gLogAction->LogText("\p\r### DNSAction DNRPRoxyRxThread unexpected event code: ", result);
  402.                 break;
  403.         }    // end switch
  404.  
  405.         if (result != 0) {
  406.             // Thread died due to Endpoint event, try to recover
  407.             if (mIsServing) {
  408.                 StopServing(true);
  409.                 mIdleDelay = kDNSIdleRestart;        // set idle time for restart
  410.                 OTGetTimeStamp(&mLastStamp);
  411.                 mWaitingToRestart = true;
  412.                 //this->StartIdling();
  413.                 this->StartRepeating();
  414.                 //StartServing();
  415.             }
  416.         }
  417.     }
  418. }
  419.  
  420.  
  421. // ---------------------------------------------------------------------------------
  422. //        • LastComplete
  423. // ---------------------------------------------------------------------------------
  424. //    Release our UDP endpoint only after all threads have safely completed
  425. void
  426. CDNSAction::LastComplete()
  427. {
  428.     if ((mReceiveUDPThread == nil) &&
  429.         (mSendUDPThread == nil)) {
  430.         // Release the UDP Endpoint we created
  431.         if (mUDPEndpoint) {
  432.             mUDPEndpoint->RemoveListener(this);
  433.             delete mUDPEndpoint;
  434.             mUDPEndpoint = nil;
  435.         }
  436.     }
  437.     if ((mDNRProxyRxThread == nil)) {
  438.         // Release the Endpoint we created
  439.         if (mDNRProxyEndpoint) {
  440.             //mDNRProxyEndpoint->RemoveListener(this);
  441.             delete mDNRProxyEndpoint;
  442.             mDNRProxyEndpoint = nil;
  443.         }
  444.     }
  445. }
  446.  
  447.  
  448. // ---------------------------------------------------------------------------------
  449. //        • ListenToMessage
  450. // ---------------------------------------------------------------------------------
  451. //    Listen for other notifications from endpoint
  452. //        BroadcastMessage(nextMessage->GetMessageType(), nextMessage);
  453. void
  454. CDNSAction::ListenToMessage(
  455.     MessageT    inEventCode,
  456.     void        *ioParam )
  457. {
  458.     LNetMessage* inMessage = (LNetMessage*)ioParam;
  459.  
  460.     switch ( inEventCode ) {
  461.         case kOTProviderWillClose:
  462.         case kOTProviderIsClosed:
  463.             gLogAction->LogText("\p\rDNSAction:  OT Provider has closed.");
  464.             break;
  465.         case msg_BroadcasterDied:
  466.         // unknown
  467.         case 0x04:
  468.         case 0x40:
  469.             //gLogAction->LogText("\p\rDNSAction unknown async message type: ", inEventCode);
  470.             // try to recvoer
  471.             if (mIsServing) {
  472.                 //StopServing(true);
  473.                 UInt32    outRemoteAddress;
  474.                 UInt16    outRemotePort;
  475.                 SInt32    outError;
  476.                 //Str31    str;
  477.                 outRemoteAddress = 0;
  478.                 outRemotePort = 0;
  479.                 outError = 0;
  480.                 if (mUDPEndpoint) {
  481.                     mUDPEndpoint->ReceiveError(outRemoteAddress, outRemotePort, outError);
  482.                     //gLogAction->LogText("\p\rDNSAction ReceiveError from ");
  483.                     //IP_NumToStr(outRemoteAddress, str);
  484.                     //gLogAction->LogText(str);
  485.                     //gLogAction->LogText("\p:");
  486.                     //::NumToString(outRemotePort, str);
  487.                     //gLogAction->LogText(str);
  488.                     //gLogAction->LogText("\p result: ", outError);
  489.                 } else {
  490.                     StartServing();
  491.                 }
  492.             }
  493.             break;
  494.         default:
  495.             gLogAction->LogText("\p\rDNSAction unexpected async message type: ", inEventCode);
  496.             gLogAction->LogText("\p\r  Result code: ", inMessage->GetResultCode());
  497.             // try to recvoer
  498.             if (mIsServing) {
  499.                 StopServing(true);
  500.                 mIdleDelay = kDNSIdleRestart;        // set idle time for restart
  501.                 OTGetTimeStamp(&mLastStamp);
  502.                 mWaitingToRestart = true;
  503.                 //this->StartIdling();
  504.                 this->StartRepeating();
  505.                 //StartServing();
  506.             }
  507.     }
  508. }
  509.  
  510. #pragma mark --- Handle Requests ---
  511.  
  512. // ---------------------------------------------------------------------------
  513. //        • Receive Data
  514. // ---------------------------------------------------------------------------
  515. //    Handle data that arrived from the network.
  516. void
  517. CDNSAction::ReceiveData(LDataArrived* inMessage)
  518. {
  519.     dns_request_t        dnsRequest;
  520.     LInternetAddress*    inRemoteAddress;
  521.     LEndpoint*        theEndpoint;
  522.     
  523.     // test which endpoint message is from
  524.     theEndpoint = inMessage->GetEndpoint();
  525.     if (theEndpoint == mDNRProxyEndpoint) {
  526.         ReceiveDNRProxy(inMessage);
  527.         return;
  528.     }
  529.  
  530.     // initialize dnsRequest structure
  531.     OTMemzero(&dnsRequest, sizeof(dns_request_t));
  532.  
  533.     // setup access to message data and addresses
  534.     dnsRequest.md.data = (UInt8*)inMessage->GetDataBuffer();
  535.     dnsRequest.md.size = inMessage->GetDataSize();
  536.     dnsRequest.md.offset = 0;
  537.     // remote address
  538.     inRemoteAddress = inMessage->GetRemoteAddress();
  539.     dnsRequest.remoteAddr = inRemoteAddress->GetIPAddress();
  540.     dnsRequest.remotePort = inRemoteAddress->GetHostPort();
  541.     // receive time
  542.     OTGetTimeStamp(&dnsRequest.timeStamp);
  543.     
  544.     // Process Request
  545.     ProcessRequest(&dnsRequest);    
  546. }
  547.  
  548.  
  549. // ---------------------------------------------------------------------------
  550. //        • ProcessRequest
  551. // ---------------------------------------------------------------------------
  552. //    Process DNS request
  553. void
  554. CDNSAction::ProcessRequest(dns_request_t* inRequest)
  555. {
  556.     dns_header_t*        dnsHeader;
  557.     msg_descriptor_t*    md;
  558.     UInt8*                dp;
  559.     UInt16                qType, qClass;
  560.     Str255                qName;
  561.     LStr255                text;
  562.     Str31                str;
  563.     Boolean                isTypePTR = false;
  564.     OTResult            err;
  565.  
  566.     // setup to access header fields
  567.     md = &inRequest->md;
  568.     dp = (UInt8*)md->data;
  569.     dnsHeader = (dns_header_t*)md->data;
  570.     
  571.     do {
  572.         // ignore responses
  573.         if (dnsHeader->queryParameter & kQueryMaskQR) break;
  574.         // make sure there is a question
  575.         if (dnsHeader->QDCount == 0) break;
  576.         // skip header
  577.         md->offset = 12;
  578.         // get the query name
  579.         GetDName(md, qName);
  580.         // get query type and class
  581.         ::BlockMove(&dp[md->offset], &qType, 2);
  582.         ::BlockMove(&dp[md->offset+2], &qClass, 2);
  583.  
  584.         // if query is a simple name lookup
  585.         if ((qClass == kQClassIN) && (qType == kQTypeA)) {
  586.             if (false) {
  587.                 // show user
  588.                 text = "\p\rDNS query from ";
  589.                 IP_NumToStr(inRequest->remoteAddr, str);
  590.                 text += str;
  591.                 if (inRequest->remotePort != 0) {
  592.                     NumToString(inRequest->remotePort, str);
  593.                     text += "\p:";
  594.                     text += str;
  595.                 }
  596.                 gLogAction->LogText(text);
  597.                 text = "\p\r qName=";
  598.                 text += qName;
  599.                 gLogAction->LogText(text);
  600.                 gLogAction->Update();
  601.             }
  602.             // if not deferring and a real name
  603.             if (mWaitingToStop && !IsFakeDialingName(qName)) {
  604.                 // forward request to real DNS
  605.                 mDNRSourceAddr = inRequest->remoteAddr;
  606.                 mDNRSourcePort = inRequest->remotePort;
  607.                 ForwardToDNS(md->data, md->size);
  608.             }
  609.             else {
  610.                 // save in array for future processing
  611.                 // copy message content
  612.                 ::BlockMove(md->data, inRequest->buf, md->size);
  613.                 // add to array
  614.                 mResponseArray->AddItem(inRequest, sizeof(dns_request_t));
  615.                 mIdleDelay = kDNSIdleData;        
  616.     /*
  617.                 // test fake string
  618.                 text = "\p\r fake dialing name: ";
  619.                 Str255 outStr;
  620.                 text += GetFakeDialingName(qName, outStr);
  621.                 gLogAction->LogText(text);
  622.  
  623.                 text = "\p\r real dialing name: ";
  624.                 text += GetRealDialingName(outStr, qName);
  625.                 gLogAction->LogText(text);
  626.                 gLogAction->Update();        
  627.     */
  628.             }
  629.         }
  630.         else if ((qClass == kQClassIN) && (qType == kQTypePTR)) {
  631.             isTypePTR = true;
  632.         }                
  633.     } while (false);
  634.  
  635.     // Since we received a DNS request, PPP must not be connected.
  636.     // Tell PPP to connect if necessary.
  637.     if (gResInfo->IsMonitoringPPP() && !isTypePTR) {
  638.         UInt32 linkState;
  639.         linkState = gConnectionData->GetDataLinkState();
  640.         if ((linkState == kLinkStateIdle) || (linkState == kLinkStateNone)) {
  641.             err = gResInfo->ConnectPPP(nil);
  642.             if (err != kOTNoError) gLogAction->LogText("\p\rCDNSAction - unexpected PPP connect result: ", err);
  643.         }
  644.     }
  645. }
  646.  
  647.  
  648. // ---------------------------------------------------------------------------
  649. //        • SpendTime
  650. // ---------------------------------------------------------------------------
  651. //    Periodical function to test if we have a request waiting
  652. //    or other pending action.
  653. void
  654. CDNSAction::SpendTime(const EventRecord &inMacEvent)
  655. {
  656. #pragma unused (inMacEvent)
  657.     UInt32        deltaTime;
  658.     UInt32        requestAge;
  659.     ArrayIndexT    count, index;
  660.     Boolean        result;
  661.  
  662.     // do every "mIdleDelay" milliseconds
  663.     deltaTime = OTElapsedMilliseconds(&mLastStamp);
  664.     if (deltaTime > mIdleDelay) {
  665.         OTGetTimeStamp(&mLastStamp);
  666.         do {
  667.             // check if pending restart
  668.             if (mWaitingToRestart) {
  669.                 mWaitingToRestart = false;
  670.                 StartServing();
  671.                 break;    
  672.             }
  673.             // check if waiting to stop
  674. //            if (mWaitingToStop) {
  675. //                deltaTime = OTElapsedMilliseconds(&mStopStamp);
  676. //                if (deltaTime > 30000) {    // 30 seconds
  677. //                    StopServing();
  678. //                    break;
  679. //                }
  680. //            }
  681.             // check response array
  682.             if (!mResponseArray) {
  683.                 StopServing();
  684.                 break;
  685.             }
  686.             count = mResponseArray->GetCount();
  687.             if (count == 0) mIdleDelay = kDNSIdleDefault;    // no responses waiting
  688.             for (index=1; index<=count; index++) {
  689.                 dns_request_t dnsRequest;
  690.                 if (!mResponseArray->FetchItemAt(index, &dnsRequest)) continue;
  691.                 // found a request entry from array
  692.                 // set md for saved buffer
  693.                 dnsRequest.md.data = dnsRequest.buf;
  694.                 requestAge = OTElapsedMilliseconds(&dnsRequest.timeStamp);
  695.                 // if request is older than 1.5 seconds, try to send it
  696.                 if (requestAge >= 1500) {
  697.                     result = SendResponse(&dnsRequest);
  698.                     if (result) {
  699.                         // response was sent, remove from array
  700.                         mResponseArray->RemoveItemsAt(1, index);
  701.                         index -= 1;
  702.                     }
  703.                     // allow SendThread to run before trying next in array
  704.                     LThread::Yield();
  705.                 }
  706.             }
  707.         } while (false);
  708.     }    // end if (deltaTime > mIdleDelay)
  709. }
  710.  
  711.  
  712. // ---------------------------------------------------------------------------
  713. //        • SendResponse
  714. // ---------------------------------------------------------------------------
  715. //    Send DNS Response
  716. //    Try to send response, return false if SendThread is busy
  717. Boolean
  718. CDNSAction::SendResponse(dns_request_t* inRequest)
  719. {
  720.     msg_descriptor_t    md;
  721.     long                index=0;
  722.     UInt16                param;
  723.     Str255                qName;
  724.     Str255                outName;
  725.     Boolean                result;
  726.     
  727.     do {
  728.         // if thread is ready, send it
  729.         result = mSendUDPThread->IsReady();
  730.         if (!result) break;
  731.         // build response
  732.             // we start with the original query
  733.             // set parameter to indicate a response
  734.         param = kQueryMaskQR;
  735.         ::BlockMove(¶m, &inRequest->md.data[2], 2);
  736.             // indicate 1 answer
  737.         param = 1;
  738.         ::BlockMove(¶m, &inRequest->md.data[6], 2);
  739.         // we leave the question as received
  740.         // get query name
  741.         inRequest->md.offset = 12;    // start of question
  742.         result = GetDName(&inRequest->md, qName);
  743.         if (!result) {
  744.             result = 1;    // delete entry
  745.             break;        // get out
  746.         }
  747.         inRequest->md.offset += 4; // skip the qType and qClass
  748.         
  749.         // now we're ready to start loading our answer
  750.         // set md to the end of the query we received
  751.         md.data = inRequest->md.data;
  752.         md.offset = inRequest->md.offset;
  753.         md.size = kMaxResponseLen;
  754.     
  755.         // repeat the query name as the resource owner
  756.         PutDName(&md, qName);
  757.  
  758.         // check if we are connected yet and determine the CName response
  759.         UInt32 linkState;
  760.         linkState = gConnectionData->GetDataLinkState();
  761.         if (linkState == kLinkStateConnected) {
  762.             // yes, restore real domain name
  763.             GetRealDialingName(qName, outName);            
  764.         } else {
  765.             // no, use FAKE dialing name
  766.             index = GetFakeDialingName(qName, outName);
  767.             // stop deferring after two minutes (80 * 1.5sec)
  768.             if (index > 80) break;
  769.         }
  770.         // continue filling in answer Resource Record
  771.         dns_record_t* rr;
  772.         rr = (dns_record_t*)&md.data[md.offset];
  773.         rr->rdType =  kQTypeCNAME;
  774.         rr->rdClass = kQClassIN;
  775.         rr->rdTTL = 1;
  776.         // length = +1 for initial length and +1 for termination 0
  777.         rr->rdLength = outName[0] + 2;
  778.         md.offset += 10;
  779.             // write our CName response
  780.         PutDName(&md, outName);
  781.             // set message length
  782.         md.size = md.offset;        
  783.         // where to?
  784.         LInternetAddress address(inRequest->remoteAddr, inRequest->remotePort);
  785.         // send it
  786.         result = mSendUDPThread->SendUData(address, md.data, md.size);
  787.         // tell user what we did
  788.         //LogDNSResponse(inResponse);
  789.     } while (false);
  790.  
  791.     return result;
  792. }
  793.  
  794.  
  795. // ---------------------------------------------------------------------------
  796. //        • ForwardToDNS
  797. // ---------------------------------------------------------------------------
  798. //    Forward query to real DNS server
  799. OTResult
  800. CDNSAction::ForwardToDNS(UInt8* inData, UInt32 inDataSize)
  801. {
  802.     TUnitData    data;
  803.     Str31        addrStr;
  804.     LStr255        text;
  805.     UInt32        addr;
  806.     LInternetAddress    remoteHost;
  807.     EndpointRef    ep;
  808.     OTResult    result=kOTNoError;
  809.  
  810.     do {
  811.         gInterfacesAction->GetDNSAddress(addrStr);
  812.         addr = IP_StrToInt(addrStr);
  813.         if ((addr == mDNRSourceAddr) || (addr == 0)) {
  814.             gLogAction->LogText("\p\r no DNS Server available");
  815.             break;
  816.         }
  817.         if (mDNRProxyEndpoint != 0) {        
  818.             if (false) {
  819.                 // show user
  820.                 text = "\p\r Forwarding to DNS Server: ";
  821.                 text += addrStr;
  822.                 gLogAction->LogText(text);
  823.             }
  824.             // setup destination
  825.             remoteHost.SetIPAddress( addr );
  826.             remoteHost.SetHostPort( kDNSServerPort );
  827.             remoteHost.MakeOTIPAddress(data.addr);
  828.             // setup UDP data
  829.             data.opt.maxlen = 0;
  830.             data.opt.len = 0;
  831.             data.opt.buf = nil;
  832.             data.udata.maxlen = data.udata.len = inDataSize;
  833.             data.udata.buf = (unsigned char*)inData;
  834.             // get OT endpoint ref
  835.             ep = mDNRProxyEndpoint->GetEndpointRef();        
  836.             // set synchronous
  837.             ::OTSetSynchronous(ep);
  838.             ::OTSetBlocking(ep);
  839.             result = ::OTSndUData(ep, &data);        
  840.             while (result == kOTLookErr) {
  841.                 //Clear Error
  842.                 ::OTRcvUDErr(ep, NULL);            
  843.                 //Try again
  844.                 result = ::OTSndUData(ep, &data);
  845.             }    
  846.             ::DisposePtr((Ptr)data.addr.buf);        
  847.             // restore to asynchronous
  848.             OTSetNonBlocking(ep);
  849.             ::OTSetAsynchronous(ep);
  850.         }
  851.     } while (false);
  852.     return result;
  853. }
  854.  
  855.  
  856. // ---------------------------------------------------------------------------
  857. //        • ReceiveDNRProxy
  858. // ---------------------------------------------------------------------------
  859. //    Handle data that arrived from DNS
  860. void
  861. CDNSAction::ReceiveDNRProxy(LDataArrived* inMessage)
  862. {
  863.     UInt8*    dataBuf;
  864.     UInt32    dataSize;
  865.  
  866.     // setup access to message data and addresses
  867.     dataBuf = (UInt8*)inMessage->GetDataBuffer();
  868.     dataSize = inMessage->GetDataSize();
  869.     ForwardFromDNS(dataBuf, dataSize);
  870. }
  871.  
  872.  
  873. // ---------------------------------------------------------------------------
  874. //        • ForwardFromDNS
  875. // ---------------------------------------------------------------------------
  876. //    Forward response from real DNS server
  877. OTResult
  878. CDNSAction::ForwardFromDNS(UInt8* inData, UInt32 inDataSize)
  879. {
  880.     TUnitData    data;
  881.     LInternetAddress    remoteHost;
  882.     EndpointRef    ep;
  883.     OTResult    result;
  884.  
  885.     if (mUDPEndpoint != 0) {
  886.         remoteHost.SetIPAddress( mDNRSourceAddr );
  887.         remoteHost.SetHostPort( mDNRSourcePort );
  888.         
  889.         remoteHost.MakeOTIPAddress(data.addr);
  890.         data.opt.maxlen = 0;
  891.         data.opt.len = 0;
  892.         data.opt.buf = nil;
  893.         data.udata.maxlen = data.udata.len = inDataSize;
  894.         data.udata.buf = (unsigned char*)inData;
  895.  
  896.         // get OT endpoint ref
  897.         ep = mUDPEndpoint->GetEndpointRef();        
  898.         // set synchronous
  899.         ::OTSetSynchronous(ep);
  900.         ::OTSetBlocking(ep);
  901.         result = ::OTSndUData(ep, &data);        
  902.         while (result == kOTLookErr) {
  903.             //Clear Error
  904.             ::OTRcvUDErr(ep, NULL);            
  905.             //Try again
  906.             result = ::OTSndUData(ep, &data);
  907.         }    
  908.         ::DisposePtr((Ptr)data.addr.buf);        
  909.         // restore to asynchronous
  910.         ::OTSetNonBlocking(ep);
  911.         ::OTSetAsynchronous(ep);
  912.     }
  913.     return result;
  914. }
  915.  
  916.  
  917. // ---------------------------------------------------------------------------
  918. //        • GetDName
  919. // ---------------------------------------------------------------------------
  920. //    Convert a sequence of labels in Name Server format to a name string
  921. //        Return false if name exceeds maximum length (255)
  922. //        or contains an invalid pointer.
  923. Boolean
  924. CDNSAction::GetDName(msg_descriptor_t* md, Str255 outStr)
  925. {
  926.     LStr255    name;
  927.     Str255    label;
  928.     UInt8    len;
  929.     UInt16    offset, pointer, oldPointer, nameLength;
  930.     UInt16*    dp;
  931.     Boolean    isPointer;
  932.  
  933.     name = "\p";    // initialize name
  934.     nameLength = 0;
  935.     offset = md->offset;
  936.     isPointer = false;
  937.  
  938.     len = md->data[offset];    
  939.     // copy each label until end of name indicated by 0
  940.     while (len) {
  941.         // is it a pointer?
  942.         if (len >= 64) {
  943.             // yes, get pointer
  944.             if (!isPointer) {
  945.                 dp = (UInt16*)&md->data[offset];    // cast to 16-bit quantity
  946.                 offset += 2;            // advance current offset past pointer
  947.             } else {
  948.                 dp = (UInt16*)&md->data[pointer];    // cast to 16-bit quantity
  949.             }
  950.             oldPointer = pointer;
  951.             pointer = dp[0] & 0x3FFF;    // get new pointer
  952.             // pointers must refer to a prior occurance of the same name
  953.             // reject garbage pointers and pointer loops (defensive)
  954.             if (!isPointer && (pointer >= offset)) return false;
  955.             if (isPointer && (pointer >= oldPointer)) return false;
  956.             isPointer = true;
  957.         } else {
  958.             // no, copy label
  959.             if (!isPointer) {
  960.                 LString::CopyPStr(&md->data[offset], label, 64);
  961.                 offset += len + 1;    // advance offset past label
  962.             } else {
  963.                 LString::CopyPStr(&md->data[pointer], label, 64);
  964.                 pointer += len + 1;    // advance pointer past label            
  965.             }
  966.             // add label to name
  967.             name += label;
  968.             name += "\p.";    // append a dot
  969.             // check for valid length (defensive)
  970.             nameLength += len + 1;
  971.             if (nameLength > 255) return false;
  972.         }
  973.         // prepare to get next label
  974.         if (!isPointer) len = md->data[offset];
  975.         else len = md->data[pointer];
  976.     }
  977.     // if not a pointer, skip terminating zero
  978.     if (!isPointer) offset += 1;
  979.     // update ioOffset
  980.     md->offset = offset;
  981.     
  982.     // remove final dot from end of name
  983.     len = name.Length();
  984.     if (len != 0) name.Remove(len, 1);
  985.     // return the resulting name
  986.     LString::CopyPStr(name, outStr, 255);
  987.     return true;
  988. }
  989.  
  990.  
  991. // ---------------------------------------------------------------------------
  992. //        • PutDName
  993. // ---------------------------------------------------------------------------
  994. //    Write a domain name in Name Server format
  995. //    as a sequence of labels.
  996. //    Return false if name won't fit in message.
  997. Boolean
  998. CDNSAction::PutDName(msg_descriptor_t* md, ConstStr255Param inStr)
  999. {
  1000.     LStr255 name, label;
  1001.     UInt8 start, pos;
  1002.     UInt16 offset;
  1003.     UInt8* inMessage;
  1004.     
  1005.     inMessage = md->data;
  1006.     name = inStr;
  1007.     offset = md->offset;
  1008.     // copy each segment separated by '.' as a PString
  1009.     start = 1;
  1010.     pos = name.Find('.', start);
  1011.     while (pos != 0) {
  1012.         label.Assign(name, start, pos-start);
  1013.         if ((label.Length() + offset) >= md->size) return false;
  1014.         LString::CopyPStr(label, &inMessage[offset]);
  1015.         offset += pos-start + 1;
  1016.         start = pos + 1;
  1017.         pos = name.Find('.', start);
  1018.     }
  1019.     // get last segment
  1020.     label.Assign(name, start);
  1021.     if ((label.Length() + offset) >= (md->size-1)) return false;
  1022.     LString::CopyPStr(label, &inMessage[offset]);
  1023.     offset += label[0] + 1;    // adjust offset to include length
  1024.     // mark the end if necessary
  1025.     if (label[0] != 0) {
  1026.         inMessage[offset] = 0;
  1027.         offset += 1;
  1028.     }
  1029.     
  1030.     // set new offset
  1031.     md->offset = offset;
  1032.     return true;
  1033. }
  1034.  
  1035.  
  1036. // ---------------------------------------------------------------------------
  1037. //        • IsFakeDialingName
  1038. // ---------------------------------------------------------------------------
  1039. // Test if supplied string is a fake CName used for dialing.
  1040. // If so, return offset to first byte of dialing prefix, otherwise zero.
  1041. UInt8
  1042. CDNSAction::IsFakeDialingName(ConstStr255Param inStr)
  1043. {
  1044.     LStr255 str;
  1045.     UInt8    pos;
  1046.     
  1047.     str = inStr;
  1048.     pos = str.Find(kDialingPrefixStr);
  1049.     return pos;
  1050. }
  1051.  
  1052.  
  1053. // ---------------------------------------------------------------------------
  1054. //        • GetFakeDialingName
  1055. // ---------------------------------------------------------------------------
  1056. // Determine FAKE dialing name from REAL domain name, or previous FAKE
  1057. // dialing name of the form <real-name><kDialingPrefixStr>nnn<kDialingSufixStr>,
  1058. // Return nnn, the fake dialing name index
  1059. long
  1060. CDNSAction::GetFakeDialingName(ConstStr255Param inStr, Str255 outStr)
  1061. {
  1062.     LStr255 str;
  1063.     UInt8    pos;
  1064.     long    index = 0;
  1065.  
  1066.     pos = IsFakeDialingName(inStr);
  1067.     if (pos == 0) {
  1068.         // convert to fake name by adding dialing name
  1069.         str = inStr;
  1070.         str += kDialingPrefixStr;
  1071.         str += "\p1";
  1072.         index = 1;
  1073.         str += kDialingSufixStr;
  1074.     }
  1075.     else {
  1076.         Str31 s;
  1077.         // get fake string index
  1078.         pos += kDialingPrefixStr[0];    // skip dialing prefix
  1079.         str = inStr;
  1080.         str.Assign(str, 1, pos-1);        // remember start of dialing name
  1081.         index = 0;                        // convert dialing index to numvber
  1082.         while (IsDigit(inStr[pos])) {
  1083.             index *= 10;
  1084.             index += inStr[pos] - '0';
  1085.             pos += 1;
  1086.         }
  1087.         index += 1;                        // increment index
  1088.         NumToString(index, s);            // convert to string
  1089.         str += s;                        // append to start of dialing name
  1090.         str += kDialingSufixStr;        // append dialing sufix
  1091.     }
  1092.     LString::CopyPStr(str, outStr);
  1093.     return index;
  1094. }
  1095.  
  1096.  
  1097. // ---------------------------------------------------------------------------
  1098. //        • GetRealDialingName
  1099. // ---------------------------------------------------------------------------
  1100. // Determine REAL dialing name from possible FAKE dialing name of the form
  1101. // <real-name><kDialingPrefixStr>nnn<kDialingSufixStr>
  1102. StringPtr
  1103. CDNSAction::GetRealDialingName(ConstStr255Param inStr, Str255 outStr)
  1104. {
  1105.     LStr255 str;
  1106.     UInt8    pos;
  1107.  
  1108.     pos = IsFakeDialingName(inStr);
  1109.     if (pos != 0) {
  1110.         // convert to REAL name by removing dialing name
  1111.         str = inStr;
  1112.         str.Assign(str, 1, pos-1);
  1113.     }
  1114.     else {
  1115.         str = inStr;
  1116.     }
  1117.     return LString::CopyPStr(str, outStr);
  1118. }
  1119.